﻿/* Copyright 2010 Igor Francé
 * 
 * This file is part of ECMADoc (http://ecmadoc.codeplex.com).
 * 
 * ECMADoc is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * ECMADoc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with ECMADoc. 
 * If not, see http://www.gnu.org/licenses/.
 */
namespace EcmaDoc.Core
{
	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;

	using EcmaDoc.Core.Configuration;

	/// <summary>
	/// Implements various extension methods.
	/// </summary>
	public static class ExtensionsMethods
	{
		/// <summary>
		/// Attempts to convert the specified <paramref name="value"/> to <typeparamref name="T"/>, and returns a value
		/// indicating whether the conversion was successful.
		/// </summary>
		/// <typeparam name="T">The type of enum to try to convert to.</typeparam>
		/// <param name="type">The enum to try to convert to.</param>
		/// <param name="value">The value to parse.</param>
		/// <param name="returnValue">The output value that receives the result value.</param>
		/// <returns><c>true</c> if the specified <paramref name="value"/> was successfully converted to 
		/// <paramref name="returnValue"/>; otherwise <c>false</c>.</returns>
		public static bool TryParse<T>(this Enum type, string value, out T returnValue)
		{
			returnValue = default(T);

			int intEnumValue;
			if (Int32.TryParse(value, out intEnumValue))
			{
				if (Enum.IsDefined(typeof(T), intEnumValue))
				{
					returnValue = (T) (object) intEnumValue;
					return true;
				}
			}
			else
			{
				try
				{
					returnValue = (T) Enum.Parse(typeof(T), value, true);
					return true;
				}
				catch (ArgumentException)
				{
				}
			}

			return false;
		}

		/// <summary>
		/// Joins the values in the specified list into a single using the specified separator.
		/// </summary>
		/// <param name="list">The list to join.</param>
		/// <param name="separator">The separator to use to join values.</param>
		/// <returns>The values in the specified list joine into a single string using the specified separator.</returns>
		public static string Join(this IEnumerable list, string separator)
		{
			int count = list.Cast<object>().Count();

			StringBuilder result = new StringBuilder();
			int index = 0;
			foreach (object value in list)
			{
				result.Append(value == null ? string.Empty : value.ToString());
				if (++index < count)
					result.Append(separator);
			}

			return result.ToString();
		}

		/// <summary>
		/// Duplicates the specified list.
		/// </summary>
		/// <typeparam name="T">The type of the list to return</typeparam>
		/// <param name="list">The list to duplicate.</param>
		/// <returns>The suplicated list</returns>
		public static List<T> Duplicate<T>(this IEnumerable list)
		{
			List<T> result = new List<T>();
			foreach (T item in list)
				result.Add(item);

			return result;
		}

		/// <summary>
		/// Determines whether the specified <paramref name="instance"/> contains the specified <paramref name="item"/>.
		/// </summary>
		/// <param name="instance">The instance to check.</param>
		/// <param name="item">The item to check for.</param>
		/// <returns>
		/// <c>true</c> if the specified <paramref name="instance"/> contains the specified <paramref name="item"/>; 
		/// otherwise, <c>false</c>.
		/// </returns>
		public static bool ContainsItem(this List<List<object>> instance, object item)
		{
			foreach (List<object> list in instance)
			{
				foreach (object value in list)
				{
					if (value == item)
						return true;
				}
			}

			return false;
		}

		/// <summary>
		/// Determines whether the specified <paramref name="instance"/> contains the specified <paramref name="item"/>
		/// after the specified <paramref name="index"/>.
		/// </summary>
		/// <param name="instance">The instance to check.</param>
		/// <param name="item">The item to check for.</param>
		/// <param name="index">The index after which the specified <paramref name="item"/> is being searched for.</param>
		/// <returns>
		/// <c>true</c> if the specified <paramref name="instance"/> contains the specified <paramref name="item"/>
		/// after the specified <paramref name="index"/>; otherwise, <c>false</c>.
		/// </returns>
		public static bool ContainsItemAfterIndex(this List<List<object>> instance, object item, int index)
		{
			bool contains = false;
			int after = index + 1;
			foreach (List<object> list in instance)
			{
				if (list.Count > after)
				{
					for (int i = after; i < list.Count; i++)
					{
						if (list[i] == item)
						{
							contains = true;
							break;
						}
					}
				}

				if (contains)
					break;
			}

			return contains;
		}

		/// <summary>
		/// Flattens the specified list of lists into a single list.
		/// </summary>
		/// <typeparam name="T">The type of the list to return</typeparam>
		/// <param name="instance">The instance to flatten.</param>
		/// <returns>The flattened version of the specified <paramref name="instance"/>.</returns>
		public static List<T> Flatten<T>(this List<List<object>> instance)
		{
			List<T> result = new List<T>();
			foreach (List<object> list in instance)
			{
				foreach (object value in list)
				{
					if (value is T && !result.Contains((T) value))
						result.Add((T) value);
				}
			}

			return result;
		}

		/// <summary>
		/// Determines whether the specified <paramref name="instance"/> contain the specified <paramref name="path"/>
		/// </summary>
		/// <param name="instance">The instance to check.</param>
		/// <param name="path">The path to check for.</param>
		/// <returns>
		/// <c>true</c> if the specified <paramref name="instance"/> contain the specified <paramref name="path"/>; otherwise, <c>false</c>.
		/// </returns>
		public static bool Contains(this List<PathInfo> instance, string path)
		{
			bool contains = false;
			foreach (PathInfo info in instance)
			{
				if (info.Path == path)
				{
					contains = true;
					break;
				}
			}

			return contains;
		}

		/// <summary>
		/// Removes the specified <paramref name="path"/> from the specified <paramref name="instance"/>.
		/// </summary>
		/// <param name="instance">The instance from which to remove the specified <paramref name="path"/>.</param>
		/// <param name="path">The path to remove from the specified <paramref name="instance"/>.</param>
		public static void Remove(this List<PathInfo> instance, string path)
		{
			int index = instance.IndexOf(instance.Where(i => i.Path == path).FirstOrDefault());
			if (index != -1)
				instance.RemoveAt(index);
		}
	}
}
